package com.xzakota.minesweeper.ui.dialog.templae;

import com.xzakota.minesweeper.R;
import com.xzakota.minesweeper.controller.GameResource;
import com.xzakota.minesweeper.ui.IWindow;
import com.xzakota.minesweeper.ui.IWindowClosingListener;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.*;

/**
 * 抽象自定义对话框
 *
 * @author Xzakota
 */
public abstract class AbstractBaseDialog extends JDialog implements IWindow {
    public static int DIALOG_MAX_WIDTH = 500;
    public static int DIALOG_MAX_HEIGHT = 500;

    private final Window parent;

    private final JScrollPane scrollPane;
    private final JPanel scrollViewportPanel;

    private final JTextArea messageLabel;
    private final JPanel buttonsPanel;
    public Object dialogResult = null;
    private final JButton okButton;
    private boolean hasOkButton;
    private final JButton cancelButton;
    private boolean hasCancelButton;
    private final JButton extraButton;
    private boolean hasExtraButton;

    public AbstractBaseDialog() {
        this(null);
    }

    public AbstractBaseDialog(Window parent) {
        this(parent, true);
    }

    public AbstractBaseDialog(Window parent, boolean isModal) {
        super(parent, "", isModal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS);
        this.parent = parent;

        setIconImage(GameResource.getImageResource(R.Image.APP_ICON));

        JPanel rootPanel = new JPanel();
        rootPanel.setLayout(new BorderLayout());
        rootPanel.setBorder(new EmptyBorder(15, 15, 15, 15));

        scrollViewportPanel = new JPanel();
        scrollViewportPanel.setLayout(new BoxLayout(scrollViewportPanel, BoxLayout.Y_AXIS));
        messageLabel = new JTextArea();
        // messageLabel.setLineWrap(true);
        messageLabel.setEditable(false);
        messageLabel.setOpaque(false);
        scrollViewportPanel.add(messageLabel);

        scrollPane = new JScrollPane(scrollViewportPanel);
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        scrollViewportPanel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                super.componentResized(e);

                updateUI();
            }
        });

        rootPanel.add(scrollPane, BorderLayout.CENTER);

        buttonsPanel = new JPanel();
        buttonsPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 10, 0));
        buttonsPanel.setBorder(new EmptyBorder(10, 0, 0, 0));
        rootPanel.add(buttonsPanel, BorderLayout.SOUTH);

        okButton = new JButton();
        okButton.setFocusable(false);

        cancelButton = new JButton();
        cancelButton.setFocusable(false);

        extraButton = new JButton();
        extraButton.setFocusable(false);

        setContentPane(rootPanel);
        updateUI();

        setResizable(false);
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension preferredSize = super.getPreferredSize();
        return new Dimension(
                Math.min(preferredSize.width, DIALOG_MAX_WIDTH),
                Math.min(preferredSize.height, DIALOG_MAX_HEIGHT)
        );
    }

    protected void updateUI() {
        pack();
        setLocationRelativeTo(parent);
    }

    public void setWindowClosingListener(IWindowClosingListener listener) {
        for (WindowListener l : getWindowListeners()) {
            removeWindowListener(l);
        }

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                listener.windowClosing(e);
            }
        });
    }

    @Override
    public void showWindow() {
        setVisible(true);
    }

    public Object showWindow2() {
        setVisible(true);

        return dialogResult;
    }

    @Override
    public void hideWindow() {
        setVisible(false);
    }

    @Override
    public void closingWindow() {
        dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
    }

    @Override
    public void closeWindow() {
        dispose();
    }

    @Override
    public boolean isShowing() {
        return isVisible();
    }

    public void closeDialogAndSetResult(final Object result) {
        dialogResult = result;
        closeWindow();
    }

    public void setMessage(String message) {
        messageLabel.setText(message);
        scrollPane.getVerticalScrollBar().setValue(0);
    }

    public void setComponent(Component c) {
        setComponent(c, null);
    }

    public void setComponent(Component c, Object constraints) {
        scrollViewportPanel.add(c);
        scrollPane.getVerticalScrollBar().setValue(0);
        updateUI();
    }

    public void setConfirmButton(String text) {
        okButton.setText(text);
        if (!hasOkButton) {
            buttonsPanel.add(okButton);
            hasOkButton = true;
        }
        updateUI();
    }

    public void setConfirmAction(ActionListener listener) {
        removeConfirmAllAction();
        okButton.addActionListener(listener);
    }

    public void setConfirmButtonEnabled(boolean enabled) {
        okButton.setEnabled(enabled);
    }

    public void removeConfirmAllAction() {
        for (ActionListener listener : okButton.getActionListeners()) {
            okButton.removeActionListener(listener);
        }
    }

    public void setCancelButton(String text) {
        cancelButton.setText(text);
        if (!hasCancelButton) {
            buttonsPanel.add(cancelButton);
            hasCancelButton = true;
        }
        buttonsPanel.add(cancelButton);
        updateUI();
    }

    public void setCancelAction(ActionListener listener) {
        removeCancelAllAction();
        cancelButton.addActionListener(listener);
    }

    public void removeCancelAllAction() {
        for (ActionListener listener : cancelButton.getActionListeners()) {
            cancelButton.removeActionListener(listener);
        }
    }

    public void setExtraButton(String text) {
        extraButton.setText(text);
        if (!hasExtraButton) {
            buttonsPanel.add(extraButton);
            hasExtraButton = true;
        }
        buttonsPanel.add(extraButton);
        updateUI();
    }

    public void setExtraAction(ActionListener listener) {
        extraButton.addActionListener(listener);
    }

    public void style1Buttons() {
        setConfirmButton("确认");
        setConfirmAction(e -> closeDialogAndSetResult(true));
    }

    public void style2Buttons() {
        setCancelButton("取消");
        setCancelAction(e -> closeDialogAndSetResult(false));
    }

    public void style3Buttons() {
        style1Buttons();
        style2Buttons();
    }
}
